package com.taoes.simpledocker.service.imple;

import cn.hutool.core.util.StrUtil;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.*;
import com.github.dockerjava.api.model.*;
import com.taoes.simpledocker.aop.annotation.OperateRecorder;
import com.taoes.simpledocker.config.DockerClientFactory;
import com.taoes.simpledocker.controller.container.RunNewContainerRequest;
import com.taoes.simpledocker.model.enums.OperatorResource;
import com.taoes.simpledocker.service.ContainerService;
import com.taoes.simpledocker.service.OperateRecordService;
import com.taoes.simpledocker.utils.BooleanUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.util.List;
import java.util.Map;

/**
 * 容器服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ContainerServiceImpl implements ContainerService {

    private final DockerClientFactory clientFactory;

    private final OperateRecordService operateRecordService;

    @Override //1
    public List<Container> list(boolean showAll) {
        final DockerClient client = clientFactory.get();
        return client.listContainersCmd().withShowAll(showAll).exec();
    }

    @OperateRecorder(type = OperatorResource.CONTAINER)
    @Override
    public CreateContainerResponse run(RunNewContainerRequest request) {
        final DockerClient client = clientFactory.get();

        HostConfig hostConfig = HostConfig.newHostConfig();
        hostConfig.withBinds(request.findBinds())
                .withPortBindings(request.findPortBindings());/*.withLinks(Link.parse(""))*/


        CreateContainerCmd createContainerCmd = client.createContainerCmd(request.getImageId())
                .withEnv(request.findEnvList());

        if (!StrUtil.isEmpty(request.getContainerName())) {
            createContainerCmd.withName(request.getContainerName());
        }


        if (!request.isPro()) {
            return createContainerCmd.withHostConfig(hostConfig).exec();
        }

        Long cpuCount = request.getCpuCount();
        if (cpuCount > 0) {
            // cpu
            hostConfig.withCpuCount(request.getCpuCount());

        }

        if (request.getMemory() > 0) {
            // 内存
            hostConfig.withMemory(request.getMemory());

        }

        // 重启策略重启次数，网络默认为bridge
        hostConfig.withRestartPolicy(RestartPolicy.onFailureRestart(request.getMaximumRetryCount()))
                .withNetworkMode(request.getNetworkMode());

        // 别名
        if (!StrUtil.isBlank(request.getAlias())) {
            createContainerCmd.withAliases(request.getAlias());
        }
        // 主机名
        if (!StrUtil.isBlank(request.getHostname())) {
            createContainerCmd.withAliases(request.getAlias());
        }
        final CreateContainerResponse response = createContainerCmd
                .withHostConfig(hostConfig)
                .exec();

        return response;
    }

    @Override
    public void start(String containerId) {
        final DockerClient client = clientFactory.get();
        client.startContainerCmd(containerId).exec();
        log.info("启动容器,containerId={}", containerId);

        // 记录日志

    }

    //0


    @Override
    public void stop(String containerId) {
        final DockerClient client = clientFactory.get();
        client.stopContainerCmd(containerId).exec();
        log.info("停止容器,containerId={}", containerId);
    }

    @Override
    public void pause(String containerId) {
        final DockerClient client = clientFactory.get();
        client.pauseContainerCmd(containerId).exec();
        log.info("暂停容器,containerId={}", containerId);
    }

    @Override
    public void unpause(String containerId) {
        final DockerClient client = clientFactory.get();
        client.unpauseContainerCmd(containerId).exec();
        log.info("继续容器,containerId={}", containerId);
    }

    @OperateRecorder(type = OperatorResource.CONTAINER)
    @Override
    public void remove(String containerId, Map<String, String> params) {
        final String force = params.get("force");
        final String removeVolume = params.get("removeVolume");

        final DockerClient client = clientFactory.get();
        client.removeContainerCmd(containerId).withForce(BooleanUtils.parse(force, false))
                .withRemoveVolumes(BooleanUtils.parse(removeVolume, false)).exec();
        log.info("移除容器,containerId={} params={}", containerId, params);

    }


    @Override
    public void rename(String containerId, String newName) {

        final DockerClient dockerClient = clientFactory.get();
        dockerClient.renameContainerCmd(containerId).withName(newName).exec();
        log.info("重命名容器:[{}]为[{}]", containerId, newName);
    }


    @Override
    public TopContainerResponse top(String containerId, String psArgs) {
        final DockerClient dockerClient = clientFactory.get();
        return dockerClient.topContainerCmd(containerId).withPsArgs(psArgs).exec();
    }

    @Override
    public InspectContainerResponse inspect(String containerId) {
        final DockerClient client = clientFactory.get();
        final InspectContainerResponse response =
                client.inspectContainerCmd(containerId).withSize(Boolean.TRUE).exec();
        return response;
    }


    @Override
    public void restart(String containerId) {
        final DockerClient client = clientFactory.get();
        client.restartContainerCmd(containerId).exec();

    }

    @Override
    public void connectToNetwork(String containerId, String networkId) {
        final DockerClient client = clientFactory.get();
        client.connectToNetworkCmd()
                .withContainerId(containerId)
                .withNetworkId(networkId)
                .exec();

    }

    @Override
    public void disconnectFromNetwork(String containerId, String networkId) {
        final DockerClient client = clientFactory.get();
        client.disconnectFromNetworkCmd()
                .withContainerId(containerId)
                .withNetworkId(networkId)
                .exec();

    }

    @Override
    @OperateRecorder(type = OperatorResource.CONTAINER)
    public InputStream copyFileFromContainer(String containerId, String source) {
        final DockerClient client = clientFactory.get();
        InputStream inputStream = client.copyArchiveFromContainerCmd(containerId, source).exec();
        return inputStream;
    }

    @Override
    @OperateRecorder(type = OperatorResource.CONTAINER)
    public void prune() {
        final DockerClient client = clientFactory.get();
        PruneResponse pruneResponse = client.pruneCmd(PruneType.CONTAINERS).exec();
    }

    @Override
    public String commit(String containerId) {
        final DockerClient client = clientFactory.get();
        CommitCmd commitCmd = client.commitCmd(containerId);
        String exec = commitCmd.exec();
        return exec;
    }

    public InputStream exportAfterCommit(String containerId) {
        final DockerClient client = clientFactory.get();
        CommitCmd commitCmd = client.commitCmd(containerId).withTag("new").withRepository(containerId);
        String newId = commitCmd.exec();
        SaveImageCmd saveImageCmd = client.saveImageCmd(newId);
        return saveImageCmd.exec();
    }
}
